package conector;

import java.awt.image.BufferedImage;
import java.net.URL;
import java.util.ArrayList;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Hashtable;
import java.util.List;

import vuelos.ControladorVuelos;

import com.jksoft.meteo.data.WeatherEntry;
import com.minube.flights.data.FlightEntry;


import lector.ControladorLector;
import lector.MiEvento;
import map.ControladorMapas;
import memoria.BBDD;
import meteo.ControladorMeteo;


/**
 * Agente mediador de todo agente
 * 
 * @author Alberto Cabrera Perez
 * 
 * @version 0.001a
 */


public class ControladorConector {
	
	private String user;
	private long oneDayLong;
	
	// Variables del uso del controlador meteorologico
	private ControladorMeteo meteo;
	private String normalForeLocation;
	private List<WeatherEntry> normalForecast;
	private String cribbedForeLocation;
	private Date cribbedForeDate;
	private List<WeatherEntry> cribbedForecast;
	
	// Variables de uso del controlador lector
	private ControladorLector lector;
	private ArrayList<String> locations;
	private ArrayList<String> spacedLocations;
	private ArrayList<MiEvento> eventos;
	private String[] calendars;
	
	//Variables de uso del controlador de mapas
	private ControladorMapas mapas;
	
	//Variables del uso de la Memoria
	private BBDD memoria;
	private String calendar;
	private String userLocation;
	private Boolean recuerdaCalendario;
	private Boolean recuerdaLocation;
	
	//Variables del uso del contrlador de vuelo
	private ControladorVuelos vuelos;
	private Hashtable<String, Date> flightDateMemory;
	private Hashtable<String, List<FlightEntry> > flightMemory;
	
	public ControladorConector(String user, String password) {
		this.user = user;
		lector = new ControladorLector(user, password);
		mapas = new ControladorMapas();
		meteo = new ControladorMeteo();
		vuelos = new ControladorVuelos();
		
		GregorianCalendar gc1 = new GregorianCalendar(2000, 0, 1);
		GregorianCalendar gc2 = new GregorianCalendar(2000, 0, 2);
		oneDayLong = gc2.getTime().getTime() - gc1.getTime().getTime();
	}
	
	/*
	 * METODOS DE VUELO
	 */
	public List<FlightEntry> getFlights (String eventLocation, String source, String destination) {
		MiEvento src = getEventInLocation(eventLocation);
		List<FlightEntry> flights = null;
//		if (flightDateMemory != null && flightDateMemory.containsValue(source)) {
//				flights = flightMemory.get(source);
//		} else {
			if (flightDateMemory == null)
				flightDateMemory = new Hashtable<String, Date>();
			if (flightMemory == null)
				flightMemory = new Hashtable<String, List<FlightEntry>>();
//			System.out.println(source + "," + destination + "," + src.getFechaInicio() + "," + src.getFechaFin());
			flights = vuelos.getFlights(source, destination, src.getFechaInicio(), src.getFechaFin());
			flightMemory.remove(source);
			flightMemory.put(source, flights);
			flightDateMemory.put(source, src.getFechaInicio());
//		}
		return flights;
	}
	
	public List<FlightEntry> getFlights (String eventLocation, String source, String destination, int desp) {
		MiEvento src = getEventInLocation(eventLocation);
		List<FlightEntry> flights = null;
		if (flightDateMemory != null && flightDateMemory.containsValue(source)) {
				flights = flightMemory.get(source);
		} else {
			if (flightDateMemory == null)
				flightDateMemory = new Hashtable<String, Date>();
			if (flightMemory == null)
				flightMemory = new Hashtable<String, List<FlightEntry>>();
			Date initDesp = new Date(src.getFechaInicio().getTime() - desp * oneDayLong);
			Date endDesp =  new Date(src.getFechaFin().getTime() + desp * oneDayLong);
			List<FlightEntry> f1 = vuelos.getFlights(source, destination, src.getFechaInicio(), endDesp);
			List<FlightEntry> f2 = vuelos.getFlights(source, destination, initDesp, src.getFechaFin());
			List<FlightEntry> f3 = vuelos.getFlights(source, destination, initDesp, endDesp);
			flights = f1;
			for (FlightEntry f : f2)
				flights.add(f);
			for (FlightEntry f : f3)
				flights.add(f);
			flightMemory.remove(source);
			flightMemory.put(source, flights);
			flightDateMemory.put(source, src.getFechaInicio());
		}
		return flights;
	}
	
	
	/*
	 * Metodos de meteorologia
	 * 
	 */
	public List<WeatherEntry>getForecast (String location) {
		if (normalForecast == null || !normalForeLocation.equals(location)) {
			normalForecast = meteo.getForecast(location);
			normalForeLocation = location;
		}
		return normalForecast;
	}
	
	public List<WeatherEntry> getForecastCribbed (String location, Date date) {
		if (cribbedForecast == null || !cribbedForeLocation.equals(location) || !cribbedForeDate.equals(date)) {
			cribbedForecast = meteo.getForecastCribbed(location, date);
			cribbedForeLocation = location;
			cribbedForeDate = date;
		}
		return cribbedForecast;
	}
	
	/*
	 * METODOS DE MAPAS
	 */
	public URL getMapURL() {
		return mapas.getRoute(locations);
	}
	
	
	public BufferedImage getLocationMap() {
		return mapas.getMapImage(locations);
	}
	
	public void compruebaUsuario() {
		if (memoria == null)
			memoria = new BBDD();
		if (memoria.esNuevoUsuario(user)) {
			memoria.setNuevoUsuario(user);
		}
	}
	
	/*
	 * METODOS DE MEMORIA
	 */
	public boolean recuerdaCalendario() {
		if (memoria == null)
			memoria = new BBDD();
		if (recuerdaCalendario == null) {
			recuerdaCalendario = new Boolean(!memoria.esVaciaCalendar(user));
			if (recuerdaCalendario)
				this.calendar = memoria.getCalendar(user);
		}
		return recuerdaCalendario;
	}
	
	public void setCalendario(String calendar) {
		if (memoria == null)
			memoria = new BBDD();
		if (recuerdaCalendario == null)
			recuerdaCalendario();
		if (this.calendar == null || !this.calendar.equals(calendar)) {
			memoria.setCalendar(user, calendar);
			recuerdaCalendario = new Boolean(true);
			this.calendar = calendar;
		}
	}
	
	public boolean recuerdaLocation() {
		if (memoria == null)
			memoria = new BBDD();
		if (recuerdaLocation == null) {
			recuerdaLocation = new Boolean(!memoria.esVaciaLocation(user));
			if (recuerdaLocation)
				userLocation = memoria.getLocation(user);
		}
		return recuerdaLocation;
	}
	
	public void setLocation(String location) {
		if (memoria == null)
			memoria = new BBDD();
		if (recuerdaLocation == null)
			recuerdaLocation();
		if (this.userLocation == null || !userLocation.equals(location)) {
			memoria.setLocation(user, location);
			recuerdaLocation = new Boolean(true);
			userLocation = location;
		}
	}
	
	/*
	 * Metodos del Lector
	 */
	public String[] getCalendars() {
		if (calendars == null)
			calendars = lector.getGoogleCalendars();
		return calendars;
	}
	
	public boolean conectarGoogleCalendar() {
		return lector.conectarGoogleCalendar();
	}
	
	public ArrayList<String> getLocations() {
		if (locations == null) {
			getEventLocations();
		}
		return locations;
	}
	
	public ArrayList<String> getSpacedLocations() {
		if (spacedLocations == null) {
			getEventLocations();
		}
		return spacedLocations;
	}
	
	public ArrayList<MiEvento> getEventLocations() {
		if (eventos == null) {
			eventos = lector.consultaGoogleCalendars();
			locations = new ArrayList<String>();
			spacedLocations = new ArrayList<String>();
			locations.add(spaceToPlus(userLocation));
			spacedLocations.add(userLocation);
			for (MiEvento e : eventos) {
				locations.add(spaceToPlus(e.getLocation()));
				spacedLocations.add(e.getLocation());
			}
		}
		return eventos;
	}
	

	/*
	 * AUXILIARES
	 */
	
	private String spaceToPlus(String s) {
		String toRet = s;
		if (s.contains(" ")) {
			String[] noSpaceLocation = s.split(" ");
			toRet = noSpaceLocation[0];
			for (int i = 1; i < noSpaceLocation.length; i++) {
				toRet += "+" + noSpaceLocation[i];
			}
		}
		return toRet;
	}
	
	private MiEvento getEventInLocation(String s) {
		MiEvento e = null;
		for (MiEvento f : eventos)
			if (f.getLocation().equals(s)) {
				e = f;
				break;
			}
		if (e == null) {
			e = new MiEvento();
			e.setLocation(s);
			e.setTitle("Situacion actual");
			e.setDates(new Date(), new Date());
		}
		return e;
	}
	
}

